//
// Created by 17775 on 2024/10/23.
//

#include "Beam_Quality.h"
#include<string.h>
#include<QDebug>

#include "LiveMode_Measurement.h"

void Beam_Quality::setFrameSpan(int frame) {
    bool bFrameSpanAvailable = false;
    RayCi_BeamQuality_Recording_Settings_isFrameSpanAvailable(_iBeamQualityDocId, &bFrameSpanAvailable);
    if(bFrameSpanAvailable) {
        if(frame == 0) {
            setSingleShot(true);
        } else {
            RayCi_BeamQuality_Recording_Settings_setFrameSpan(_iBeamQualityDocId, frame);
        }
    }
}

int Beam_Quality::getTimeSpan() {
    bool bTimeSpanAvailable = false;
    int timeindex=-1;
    RayCi_BeamQuality_Recording_Settings_isTimeSpanAvailable(_iBeamQualityDocId, &bTimeSpanAvailable);
    if(bTimeSpanAvailable) {
        double dTimeSpan = 0.0;
        RayCi_BeamQuality_Recording_Settings_getTimeSpan(_iBeamQualityDocId, &dTimeSpan);
        double durations[] = {0, 1, 2, 5, 10, 25, 60, 120, 300, 600, 1500, 3600};

        double minDiff = fabs(dTimeSpan - durations[0]);
        timeindex = 0;
        for (int i = 1; i < sizeof(durations)/sizeof(durations[0]); i++) {
            double diff = fabs(dTimeSpan - durations[i]);
            if (diff < minDiff) {
                minDiff = diff;
                timeindex = i;
            }
        }
    }
    return timeindex;
}


void Beam_Quality::setTimeSpan(double dTime) {
    bool bTimeSpanAvailable = false;
    RayCi_BeamQuality_Recording_Settings_isTimeSpanAvailable(_iBeamQualityDocId, &bTimeSpanAvailable);
    if(bTimeSpanAvailable) {
        if(dTime == 0) {
            setSingleShot(true);
        } else {
            RayCi_BeamQuality_Recording_Settings_setTimeSpan(_iBeamQualityDocId, dTime);
        }
    }
}

void Beam_Quality::setSingleShot(bool bSingleShot) {
    bool bSingleShotAvailable = false;
    RayCi_BeamQuality_Recording_Settings_isSingleShotAvailable(_iBeamQualityDocId, &bSingleShotAvailable);
    if(bSingleShotAvailable) {
        RayCi_BeamQuality_Recording_Settings_setSingleShot(_iBeamQualityDocId, bSingleShot);
    }
}

QString Beam_Quality::getRecordingRemark() const {
        char szRemark_buffer[80] = {0};
        int nSize = sizeof(szRemark_buffer);
        bool success = RayCi_BeamQuality_Recording_getRemarkA(_iBeamQualityDocId, szRemark_buffer, &nSize);
        return success ? QString::fromLatin1(szRemark_buffer) : QString();
}


int Beam_Quality::getMeasureMethodIndex() const {
    int nMethodIndex = 0;
    RayCi_BeamQuality_Analysis_Settings_getMethod(_iBeamQualityDocId, &nMethodIndex);
    return  nMethodIndex;
}

bool  Beam_Quality::getRawBeamMeasureResult() const {
    bool bRawBeamMeasureResult = false;
    RayCi_BeamQuality_Analysis_Settings_isRawBeamResults(_iBeamQualityDocId, &bRawBeamMeasureResult);
    return bRawBeamMeasureResult;
}

void  Beam_Quality::setBeamQualityMethod(int nMethodIndex) {
    RayCi_BeamQuality_Analysis_Settings_setMethod(_iBeamQualityDocId, nMethodIndex);
}

void  Beam_Quality::setBeamQualityRawBeamResult(bool bRawBeamMeasureResult) {
    if (bRawBeamMeasureResult) {
        RayCi_BeamQuality_Analysis_Settings_setRawBeamResults(_iBeamQualityDocId, bRawBeamMeasureResult);
    }
    else {
        RayCi_BeamQuality_Analysis_Settings_setRawBeamResults(_iBeamQualityDocId, false);
        setLaserWavelength(BeamQualityWavelength);
        setFocalLength(BeamQualityFocalLength);
    }
}


double Beam_Quality::getLaserWavelength() {
    double dBeamQuality = 0.0;
    RayCi_BeamQuality_Header_Laser_getWaveLength(_iBeamQualityDocId, &dBeamQuality);
    return dBeamQuality;
}


double Beam_Quality::getFocalLength() {
    double dBeamQuality = 0.0;
    RayCi_BeamQuality_Header_Lens_getFocalLength(_iBeamQualityDocId, &dBeamQuality);
    return dBeamQuality;
}

void Beam_Quality::setLaserWavelength(double dLaserWavelength) {

    double dUncertainty = 0.0;
    BeamQualityWavelength= dLaserWavelength;
    bool getSuccess = RayCi_BeamQuality_Header_Laser_getWaveLengthUncertainty(
        _iBeamQualityDocId,
        &dUncertainty
    );

    if (!getSuccess) {
        qDebug() << "Failed to get current wavelength uncertainty, using default value of 0.1nm";
    }

    RayCi_BeamQuality_Header_Laser_setWaveLength(
        _iBeamQualityDocId,
        dLaserWavelength,
        dUncertainty
    );
}

void Beam_Quality::setFocalLength(double dFocalLength) {

    double dUncertainty = 0.0;
    BeamQualityFocalLength= dFocalLength;
    bool getSuccess = RayCi_BeamQuality_Header_Laser_getWaveLengthUncertainty(
        _iBeamQualityDocId,
        &dUncertainty
    );

    if (!getSuccess) {
        qDebug() << "Failed to get current wavelength uncertainty, using default value of 0.1nm";
    }

    RayCi_BeamQuality_Header_Lens_setFocalLength(
        _iBeamQualityDocId,
        dFocalLength,
        dUncertainty
    );
}


void Beam_Quality::stopBeamQuality() {
    RayCi_BeamQuality_Recording_stop(_iBeamQualityDocId);
}

void Beam_Quality::clearBeamQuality() {
    RayCi_BeamQuality_Recording_clear(_iBeamQualityDocId);
}

void Beam_Quality::setLinkStart(bool bLink) {
    RayCi_BeamQuality_Recording_Settings_setLinkStart(_iBeamQualityDocId, bLink);
}

void Beam_Quality::setLinkStop(bool bLink) {
    RayCi_BeamQuality_Recording_Settings_setLinkStop(_iBeamQualityDocId, bLink);
}
// 获取ISO一致性信息
QString Beam_Quality::getIsoConformityString(int docId, bool (*getIsoConformityFunc)(int, char*, int*)) const {
    int bufferSize = 0;
    getIsoConformityFunc(docId, NULL, &bufferSize);
    if (bufferSize <= 0) {
        return "Not Conform: Failed to determine ISO conformity buffer size";
    }

    char* buffer = new char[bufferSize];
    bool success = getIsoConformityFunc(docId, buffer, &bufferSize);
    QString result = success ? QString::fromLatin1(buffer) :
                              "Not Conform: Failed to retrieve ISO conformity information";
    delete[] buffer;
    return result;
}

// 获取参数值（带有效性检查）
template<typename T>
QString Beam_Quality::getParameterValue(int docId, bool (*isValidFunc)(int, bool, bool*),
                                      bool (*getValueFunc)(int, bool, T*),
                                      bool withUncertainty) const {
    bool isValid = false;
    isValidFunc(docId, withUncertainty, &isValid);
    if (!isValid) {
        return withUncertainty ? "" : "(The fit could not be performed)";
    }

    T value = T();
    getValueFunc(docId, withUncertainty, &value);
    return QString::number(value);
}

// 获取参数值和不确定性
template<typename T>
std::pair<QString, QString> Beam_Quality::getParameterWithUncertainty(int docId,
    bool (*isValidFunc)(int, bool, bool*),
    bool (*getValueFunc)(int, bool, T*)) const {

    return {
        getParameterValue<T>(docId, isValidFunc, getValueFunc, false),
        getParameterValue<T>(docId, isValidFunc, getValueFunc, true)
    };
}

CurrentPlaneParams Beam_Quality:: calculateBeamEllipseParameters(double dSecondMomentXX_mm, double dSecondMomentXY_mm, double dSecondMomentYY_mm) const{
    CurrentPlaneParams params;

    // 计算矩阵的迹和行列式
    double trace = dSecondMomentXX_mm + dSecondMomentYY_mm;
    double det = dSecondMomentXX_mm * dSecondMomentYY_mm - dSecondMomentXY_mm * dSecondMomentXY_mm;

    // 计算特征值（λ1 ≥ λ2）
    double discriminant = trace * trace - 4.0 * det;
    if (discriminant < 0) discriminant = 0;  // 处理数值误差

    double sqrtDisc = sqrt(discriminant);
    double lambda1 = (trace + sqrtDisc) / 2.0;
    double lambda2 = (trace - sqrtDisc) / 2.0;

    // 确保特征值为正（物理上应成立）
    if (lambda1 < 0) lambda1 = 0;
    if (lambda2 < 0) lambda2 = 0;

    // 计算两个直径（长轴和短轴）
    double diameterMajor = 4.0 * sqrt(lambda1);  // 长轴直径
    double diameterMinor = 4.0 * sqrt(lambda2);  // 短轴直径

    // 计算椭圆率（短轴/长轴）
    double ellipticity = (diameterMajor > 0) ? (diameterMinor / diameterMajor) : 1.0;

    // 计算离心率
    double eccentricity = sqrt(1.0 - ellipticity * ellipticity);

    double azimuthAngle_deg = 0.0;
    // 避免除零错误
    if (fabs(dSecondMomentXX_mm - dSecondMomentYY_mm) > 1e-10 || fabs(dSecondMomentXY_mm) > 1e-10) {
        double angle_rad = 0.5 * atan2(2.0 * dSecondMomentXY_mm,
                                      dSecondMomentXX_mm - dSecondMomentYY_mm);
        azimuthAngle_deg = angle_rad * (180.0 / M_PI);
    }

    // 更新参数结构体
    params.WidthMajor = diameterMajor;  // 长轴直径
    params.WidthMinor = diameterMinor;  // 短轴直径
    params.Ellipticity = ellipticity;
    params.Eccentricity = eccentricity;
    params.AzimuthAngle = azimuthAngle_deg;  // 方位角

    return params;
}


void Beam_Quality::getBeamQualityData() {
    bool bRecording = true;
    while(bRecording) {
        RayCi_BeamQuality_Recording_isRecording(_iBeamQualityDocId, &bRecording);
    }
    int itemCount = 0;
    RayCi_BeamQuality_Sequence_getItemCount(_iBeamQualityDocId, &itemCount);
    qDebug()<<"当前光束项目数:"<<itemCount;
    // 1. 获取当前项目索引
    int32_t nCurrentItem = -1;
    RayCi_BeamQuality_Sequence_getCurrentItem(_iBeamQualityDocId, &nCurrentItem);
    qDebug()<<"当前光束项目索引 :"<<nCurrentItem;
    // 2. 获取Z位置
    double dPositionZ_mm = 0.0;
    RayCi_BeamQuality_Sequence_Item_getPositionZ_mm(_iBeamQualityDocId, nCurrentItem, &dPositionZ_mm);
    qDebug()<<"当前光束位置:"<<dPositionZ_mm;
    // 获取是否打开
    bool itemenabled=false;
    RayCi_BeamQuality_Sequence_Item_isEnabled(_iBeamQualityDocId, nCurrentItem, &itemenabled);
    // 3. 获取二阶矩
    double dSecondMomentXX_mm = 0.0;
    double dSecondMomentXY_mm = 0.0;
    double dSecondMomentYY_mm = 0.0;

    RayCi_BeamQuality_Sequence_Item_getSecondMomentXX_mm(_iBeamQualityDocId, nCurrentItem, &dSecondMomentXX_mm);
    RayCi_BeamQuality_Sequence_Item_getSecondMomentXY_mm(_iBeamQualityDocId, nCurrentItem, &dSecondMomentXY_mm);
    RayCi_BeamQuality_Sequence_Item_getSecondMomentYY_mm(_iBeamQualityDocId, nCurrentItem, &dSecondMomentYY_mm);
    qDebug()<<"当前光束二阶矩:"<<dSecondMomentXX_mm<<dSecondMomentXY_mm<<dSecondMomentYY_mm;
    // 4. 计算光束椭圆参数
    CurrentPlaneParams params = calculateBeamEllipseParameters(dSecondMomentXX_mm, dSecondMomentXY_mm, dSecondMomentYY_mm);
    qDebug() << "当前光束参数:";
    qDebug() << "长轴直径:" << params.WidthMajor << "mm";
    qDebug() << "短轴直径:" << params.WidthMinor << "mm";
    qDebug() << "椭圆率:" << params.Ellipticity;
    qDebug() << "离心率:" << params.Eccentricity;
    qDebug() << "方位角:" << params.AzimuthAngle << "度";
    // 获取文档尺寸
    int width = 0, height = 0;
    RayCi_Single_Data_getSizeX(_iBeamQualityDocId, &width);
    RayCi_Single_Data_getSizeY(_iBeamQualityDocId, &height);
    std::vector<BYTE> previewData;

    double dX0=0., dY0=0., dMajor=0., dMinor=0., dAngle=0.;
    if ( RayCi_LiveMode_AOI_getPositionX_px(_iBeamQualityDocId, &dX0) && RayCi_LiveMode_AOI_getPositionY_px(_iBeamQualityDocId, &dY0) &&
                    RayCi_LiveMode_Analysis_SecondMoments_WidthBeam_getMajor(_iBeamQualityDocId, 0, &dMajor) &&
                    RayCi_LiveMode_Analysis_SecondMoments_WidthBeam_getMinor(_iBeamQualityDocId, 0, &dMinor) &&
         RayCi_LiveMode_AOI_getAzimuthAngle_px(0, &dAngle) ) {
        // convert angle: deg => rad
        dAngle *= M_PI/180.;
        double dPixelSizeX, dPixelSizeY;
        RayCi_LiveMode_Settings_Units_Spatial_getPixelSizeX(_iBeamQualityDocId, &dPixelSizeX);
        RayCi_LiveMode_Settings_Units_Spatial_getPixelSizeY(_iBeamQualityDocId, &dPixelSizeY);
        dMajor = dMajor * 1000 / dPixelSizeX;
        dMinor = dMinor * 1000 / dPixelSizeY;
        // calculate left, right, top, bottom extension of the AOI
        double dLeft=0., dTop=0., dRight=width-1, dBottom=height-1;
        // Ellipse
        const double ca	 = cos(dAngle);
        const double sa	 = sin(dAngle);
        const double ca2 = ca*ca;
        const double sa2 = sa*sa;
        const double csa = ca*sa;
        const double Major2 = dMajor*dMajor;
        const double Minor2 = dMinor*dMinor;
        const double XX  = Major2*ca2 + Minor2*sa2;		 // + 2*XY*csa;
        const double YY  = Major2*sa2 + Minor2*ca2;    // - 2*XY*csa;
        //const double Disc= XX*YY - XY*XY;
        const double x12	= sqrt(XX);
        const double y12	= sqrt(YY);
        dLeft  = dX0 - 0.5*x12;
        dRight = dX0 + 0.5*x12;
        dTop   = dY0 - 0.5*y12;
        dBottom= dY0 + 0.5*y12;
        // round to int
        int nLeft  = int(dLeft+1.);
        int nRight = int(dRight+1.);
        int nTop   = int(dTop+1.);
        int nBottom= int(dBottom+1.);
        // crop to image
        nLeft      = std::min(std::max(nLeft,   0), width-1);
        nRight     = std::min(std::max(nRight,  0), width-1);
        nTop       = std::min(std::max(nTop,    0), height-1);
        nBottom    = std::min(std::max(nBottom, 0), height-1);
        int nWidth = nRight - nLeft + 1;
        int nHeight= nBottom - nTop + 1;
        nWidth*=1.05;
        nHeight*=1.05;
        previewData.resize(nWidth * nHeight);
        RayCiLut::InitImage(params.my_image,_iBeamQualityDocId,nWidth, nHeight);
        if ( (nWidth>0) && (nHeight>0) )
        {
            int nSize = nWidth*nHeight;

            if ( RayCi_LiveMode_Data_getPreviewRect(_iBeamQualityDocId, nLeft, nTop, nWidth, nHeight, &previewData[0], &nSize) )
            {
                for ( int y=0; y<nHeight; y++ )
                {
                    std::memcpy(params.my_image.scanLine(y), previewData.data() + y * nWidth, nWidth * sizeof(BYTE));
                }
            }

        }
    }
    RayCi_BeamQuality_Sequence_Item_getCenterX_mm(_iBeamQualityDocId, nCurrentItem, &params.CentroidX);
    RayCi_BeamQuality_Sequence_Item_getCenterY_mm(_iBeamQualityDocId, nCurrentItem, &params.CentroidY);
    params.PositionZ=dPositionZ_mm;
    params.WidthGeneralized=(params.WidthMajor+params.WidthMinor)/2;
    params.vis=itemenabled;
    // 5. 将当前数据添加到历史记录中
    m_batchData.addItem(nCurrentItem, dPositionZ_mm, params);

    // 6. 发送更新后的批量数据
    emit getBeamQualityDataS();
}


CurrentPlaneParams Beam_Quality::getCurrentBMParams(int index) {
    CurrentPlaneParams params = {};
    params.CentroidX=m_batchData.centroidX[index];
    params.CentroidY=m_batchData.centroidY[index];
    params.PositionZ=m_batchData.positionZ[index];
    params.WidthGeneralized=m_batchData.widthGeneralized[index];
    params.WidthMajor=m_batchData.diameterMajorValue[index];
    params.WidthMinor=m_batchData.diameterMinorValue[index];
    params.AzimuthAngle=m_batchData.azimuthAngleValue[index];
    params.Ellipticity=m_batchData.ellipticityValue[index];
    params.Eccentricity=m_batchData.eccentricityValue[index];
    return params;
}

BeamQualityResult Beam_Quality::getBeamQualityResult()  {

 BeamQualityResult result = {};
    // Current Plane
    int nCurrentItem = -1;
    RayCi_BeamQuality_Sequence_getCurrentItem(_iBeamQualityDocId, &nCurrentItem);

    result.number = nCurrentItem + 1;
    result.CentroidX=m_batchData.centroidX.back();
    result.CentroidY=m_batchData.centroidY.back();
    result.PositionZ=m_batchData.positionZ.back();
    result.WidthGeneralized=m_batchData.widthGeneralized.back();
    result.WidthMajor=m_batchData.diameterMajorValue.back();
    result.WidthMinor=m_batchData.diameterMinorValue.back();
    result.AzimuthAngle=m_batchData.azimuthAngleValue.back();
    result.Ellipticity=m_batchData.ellipticityValue.back();
    result.Eccentricity=m_batchData.eccentricityValue.back();

    // General
    result.NumberofPositions = nCurrentItem + 1;
    int bufferSize = 0;
    RayCi_BeamQuality_Analysis_General_getBeamTypeAsStringA(_iBeamQualityDocId, NULL, &bufferSize);
    char* beamType = (char*)malloc(bufferSize);
    RayCi_BeamQuality_Analysis_General_getBeamTypeAsStringA(_iBeamQualityDocId, beamType, &bufferSize);
    result.GeometricBeamType = beamType;
    free(beamType);

    bool isRawBeamResultsAvailable = false;
    bool isRawBeamResults = false;
    RayCi_BeamQuality_Analysis_Settings_isRawBeamResultsAvailable(_iBeamQualityDocId, &isRawBeamResultsAvailable);
    if (isRawBeamResultsAvailable) {
        RayCi_BeamQuality_Analysis_Settings_isRawBeamResults(_iBeamQualityDocId, &isRawBeamResults);
    }
    result.Results = isRawBeamResults ? "raw beam results" : "after lens results";

    // Torsion
    RayCi_BeamQuality_Sequence_getItemCount(_iBeamQualityDocId, &result.N_elliptical);
    result.N_elliptical -= 1;
    //
    // double torsion_deg = 0.0;
    // if (fabs(dSecondMomentXX_mm - dSecondMomentYY_mm) > 1e-10 || fabs(dSecondMomentXY_mm) > 1e-10) {
    //     double torsion_rad = 0.5 * atan2(2.0 * dSecondMomentXY_mm,
    //                                     dSecondMomentXX_mm - dSecondMomentYY_mm);
    //     torsion_deg = torsion_rad * (180.0 / M_PI);
    //     while (torsion_deg > 90.0) torsion_deg -= 180.0;
    //     while (torsion_deg < -90.0) torsion_deg += 180.0;
    // }
    // result.Torsion = torsion_deg;
    result.Torsion = 0.0;
    // U Caustic
    result.uISO11146_1 = getIsoConformityString(_iBeamQualityDocId, RayCi_BeamQuality_Analysis_CausticUX_getIsoConformityAsStringA);

    // 获取光束腰位置和直径
    auto [uPos, uPos_unc] = getParameterWithUncertainty<double>(_iBeamQualityDocId,
        RayCi_BeamQuality_Analysis_CausticUX_Waist_isValid,
        RayCi_BeamQuality_Analysis_CausticUX_Waist_getPosition);
    auto [uDiam, uDiam_unc] = getParameterWithUncertainty<double>(_iBeamQualityDocId,
        RayCi_BeamQuality_Analysis_CausticUX_Waist_isValid,
        RayCi_BeamQuality_Analysis_CausticUX_Waist_getDiameter);

    result.uCausticPosition = uPos;
    result.uCausticPosition_Uncertainty = uPos_unc;
    result.uBeamWaistDiameter = uDiam;
    result.uBeamWaistDiameter_Uncertainty = uDiam_unc;

    // 获取瑞利长度
    auto [uRay, uRay_unc] = getParameterWithUncertainty<double>(_iBeamQualityDocId,
        RayCi_BeamQuality_Analysis_CausticUX_RayleighLength_isValid,
        RayCi_BeamQuality_Analysis_CausticUX_RayleighLength_getRayleighLength);
    result.uRayleighLength = uRay;
    result.uRayleighLength_Uncertainty = uRay_unc;

    // 获取发散角
    auto [uDiv, uDiv_unc] = getParameterWithUncertainty<double>(_iBeamQualityDocId,
        RayCi_BeamQuality_Analysis_CausticUX_Divergence_isValid,
        RayCi_BeamQuality_Analysis_CausticUX_Divergence_getDivergence);
    result.uDivergence = uDiv;
    result.uDivergence_Uncertainty = uDiv_unc;

    // 获取光束参数积
    auto [uBpp, uBpp_unc] = getParameterWithUncertainty<double>(_iBeamQualityDocId,
        RayCi_BeamQuality_Analysis_CausticUX_BPP_isValid,
        RayCi_BeamQuality_Analysis_CausticUX_BPP_getBPP);
    result.uBeamParameterProduct = uBpp;
    result.uBeamParameterProduct_Uncertainty = uBpp_unc;

    // 获取光束传播比
    auto [uM2, uM2_unc] = getParameterWithUncertainty<double>(_iBeamQualityDocId,
        RayCi_BeamQuality_Analysis_CausticUX_M2_isValid,
        RayCi_BeamQuality_Analysis_CausticUX_M2_getM2);
    result.uBeamPropagationRatio = uM2;
    result.uBeamPropagationRatio_Uncertainty = uM2_unc;

    // 获取光束传播因子
    auto [uK, uK_unc] = getParameterWithUncertainty<double>(_iBeamQualityDocId,
        RayCi_BeamQuality_Analysis_CausticUX_K_isValid,
        RayCi_BeamQuality_Analysis_CausticUX_K_getK);
    result.uBeamPropagationFactor = uK;
    result.uBeamPropagationFactor_Uncertainty = uK_unc;

   // V Caustic
    result.vISO11146_1 = getIsoConformityString(_iBeamQualityDocId, RayCi_BeamQuality_Analysis_CausticVY_getIsoConformityAsStringA);

    // 获取光束腰位置和直径
    auto [vPos, vPos_unc] = getParameterWithUncertainty<double>(_iBeamQualityDocId,
    RayCi_BeamQuality_Analysis_CausticVY_Waist_isValid,
    RayCi_BeamQuality_Analysis_CausticVY_Waist_getPosition);
    auto [vDiam, vDiam_unc] = getParameterWithUncertainty<double>(_iBeamQualityDocId,
    RayCi_BeamQuality_Analysis_CausticVY_Waist_isValid,
    RayCi_BeamQuality_Analysis_CausticVY_Waist_getDiameter);

    result.vCausticPosition = vPos;
    result.vCausticPosition_Uncertainty = vPos_unc;
    result.vBeamWaistDiameter = vDiam;
    result.vBeamWaistDiameter_Uncertainty = vDiam_unc;

    // 获取瑞利长度
    auto [vRay, vRay_unc] = getParameterWithUncertainty<double>(_iBeamQualityDocId,
    RayCi_BeamQuality_Analysis_CausticVY_RayleighLength_isValid,
    RayCi_BeamQuality_Analysis_CausticVY_RayleighLength_getRayleighLength);
    result.vRayleighLength = vRay;
    result.vRayleighLength_Uncertainty = vRay_unc;

    // 获取发散角
    auto [vDiv, vDiv_unc] = getParameterWithUncertainty<double>(_iBeamQualityDocId,
    RayCi_BeamQuality_Analysis_CausticVY_Divergence_isValid,
    RayCi_BeamQuality_Analysis_CausticVY_Divergence_getDivergence);
    result.vDivergence = vDiv;
    result.vDivergence_Uncertainty = vDiv_unc;

    // 获取光束参数积
    auto [bppV, bppV_unc] = getParameterWithUncertainty<double>(_iBeamQualityDocId,
    RayCi_BeamQuality_Analysis_CausticVY_BPP_isValid,
    RayCi_BeamQuality_Analysis_CausticVY_BPP_getBPP);
    result.vBeamParameterProduct = bppV;
    result.vBeamParameterProduct_Uncertainty = bppV_unc;

    // 获取光束传播比
    auto [m2V, m2V_unc] = getParameterWithUncertainty<double>(_iBeamQualityDocId,
    RayCi_BeamQuality_Analysis_CausticVY_M2_isValid,
    RayCi_BeamQuality_Analysis_CausticVY_M2_getM2);
    result.vBeamPropagationRatio = m2V;
    result.vBeamPropagationRatio_Uncertainty = m2V_unc;

    // 获取光束传播因子
    auto [kV, kV_unc] = getParameterWithUncertainty<double>(_iBeamQualityDocId,
    RayCi_BeamQuality_Analysis_CausticVY_K_isValid,
    RayCi_BeamQuality_Analysis_CausticVY_K_getK);
    result.vBeamPropagationFactor = kV;
    result.vBeamPropagationFactor_Uncertainty = kV_unc;
    // UV Caustic
    auto [astRel, astRel_unc] = getParameterWithUncertainty<double>(_iBeamQualityDocId,
        RayCi_BeamQuality_Analysis_CausticUX_VY_Astigmatism_isValid,
        RayCi_BeamQuality_Analysis_CausticUX_VY_Astigmatism_getAstigmatism);
    result.AstigmatismRel = astRel;
    result.AstigmatismRel_Uncertainty = astRel_unc;

    auto [asym, asym_unc] = getParameterWithUncertainty<double>(_iBeamQualityDocId,
        RayCi_BeamQuality_Analysis_CausticUX_VY_Asymmetry_isValid,
        RayCi_BeamQuality_Analysis_CausticUX_VY_Asymmetry_getAsymmetry);
    result.Asymmetry = asym;
    result.Asymmetry_Uncertainty = asym_unc;

    // Caustic Fit
    auto [causticPos, causticPos_unc] = getParameterWithUncertainty<double>(_iBeamQualityDocId,
        RayCi_BeamQuality_Analysis_CausticFit_Waist_isValid,
        RayCi_BeamQuality_Analysis_CausticFit_Waist_getPosition);
    result.Caustic_Position = causticPos;
    result.Caustic_Position_Uncertainty = causticPos_unc;

    auto [waistDiam, waistDiam_unc] = getParameterWithUncertainty<double>(_iBeamQualityDocId,
        RayCi_BeamQuality_Analysis_CausticFit_Waist_isValid,
        RayCi_BeamQuality_Analysis_CausticFit_Waist_getDiameter);
    result.Beam_Waist_Diameter = waistDiam;
    result.Beam_Waist_Diameter_Uncertainty = waistDiam_unc;

    auto [rayleighLen, rayleighLen_unc] = getParameterWithUncertainty<double>(_iBeamQualityDocId,
        RayCi_BeamQuality_Analysis_CausticFit_RayleighLength_isValid,
        RayCi_BeamQuality_Analysis_CausticFit_RayleighLength_getRayleighLength);
    result.Rayleigh_Length = rayleighLen;
    result.Rayleigh_Length_Uncertainty = rayleighLen_unc;

    auto [divergence, divergence_unc] = getParameterWithUncertainty<double>(_iBeamQualityDocId,
        RayCi_BeamQuality_Analysis_CausticFit_Divergence_isValid,
        RayCi_BeamQuality_Analysis_CausticFit_Divergence_getDivergence);
    result.Divergence = divergence;
    result.Divergence_Uncertainty = divergence_unc;

    // Caustic 3D Fit
    result.ISO11146_2 = getIsoConformityString(_iBeamQualityDocId,
        RayCi_BeamQuality_Analysis_Caustic3D_getIsoConformityAsStringA);

    // Rayleigh长度（左右）
    auto [rayleighLeft, rayleighLeft_unc] = getParameterWithUncertainty<double>(_iBeamQualityDocId,
        RayCi_BeamQuality_Analysis_Caustic3D_RayleighLength_isValid,
        RayCi_BeamQuality_Analysis_Caustic3D_RayleighLength_getLeft);
    result.Reyleigh_Length_3D_left = rayleighLeft;
    result.Reyleigh_Length_3D_left_Uncertainty = rayleighLeft_unc;

    auto [rayleighRight, rayleighRight_unc] = getParameterWithUncertainty<double>(_iBeamQualityDocId,
        RayCi_BeamQuality_Analysis_Caustic3D_RayleighLength_isValid,
        RayCi_BeamQuality_Analysis_Caustic3D_RayleighLength_getRight);
    result.Reyleigh_Length_3D_right = rayleighRight;
    result.Reyleigh_Length_3D_right_Uncertainty = rayleighRight_unc;

    // Twist参数
    bool isTwistZero = true;
    RayCi_BeamQuality_Header_Twist_isZero(_iBeamQualityDocId, &isTwistZero);

    if (isTwistZero) {
        result.Twist_3D = "(Assumed to be Zero)";
        result.Twist_3D_Uncertainty = "";
    } else {
        auto [twist, twist_unc] = getParameterWithUncertainty<double>(_iBeamQualityDocId,
            [](int docId, bool withUncertainty, bool* isValid) {
                return RayCi_BeamQuality_Header_Twist_isZero(docId, isValid);
            },
            [](int docId, bool withUncertainty, double* value) {
                if (withUncertainty) {
                    return RayCi_BeamQuality_Header_Twist_getTwistUncertainty(docId, value);
                } else {
                    return RayCi_BeamQuality_Header_Twist_getTwist(docId, value);
                }
            });
        result.Twist_3D = twist;
        result.Twist_3D_Uncertainty = twist_unc;
    }

    // 散光参数
    auto [astigmatismRel, astigmatismRel_unc] = getParameterWithUncertainty<double>(_iBeamQualityDocId,
        RayCi_BeamQuality_Analysis_Caustic3D_Astigmatism_isValid,
        RayCi_BeamQuality_Analysis_Caustic3D_Astigmatism_getAstigmatism);
    result.Astigmatism_rel_3D = astigmatismRel;
    result.Astigmatism_rel_3D_Uncertainty = astigmatismRel_unc;

    auto [astigmatismAngle, astigmatismAngle_unc] = getParameterWithUncertainty<double>(_iBeamQualityDocId,
        RayCi_BeamQuality_Analysis_Caustic3D_Astigmatism_isValid,
        RayCi_BeamQuality_Analysis_Caustic3D_Astigmatism_getAngle);
    result.Astigmatism_Angle_3D = astigmatismAngle;
    result.Astigmatism_Angle_3D_Uncertainty = astigmatismAngle_unc;

    // 发散角
    auto [divergence3D, divergence3D_unc] = getParameterWithUncertainty<double>(_iBeamQualityDocId,
        RayCi_BeamQuality_Analysis_Caustic3D_Divergence_isValid,
        RayCi_BeamQuality_Analysis_Caustic3D_Divergence_getDivergence);
    result.Divergence_3D = divergence3D;
    result.Divergence_3D_Uncertainty = divergence3D_unc;

    // 光束参数积
    auto [bpp3D, bpp3D_unc] = getParameterWithUncertainty<double>(_iBeamQualityDocId,
        RayCi_BeamQuality_Analysis_Caustic3D_BPP_isValid,
        RayCi_BeamQuality_Analysis_Caustic3D_BPP_getBPP);
    result.Beam_Parameter_Product_3D = bpp3D;
    result.Beam_Parameter_Product_3D_Uncertainty = bpp3D_unc;

    // 光束传播比
    auto [m23D, m23D_unc] = getParameterWithUncertainty<double>(_iBeamQualityDocId,
        RayCi_BeamQuality_Analysis_Caustic3D_M2_isValid,
        RayCi_BeamQuality_Analysis_Caustic3D_M2_getM2);
    result.Beam_Propagation_Ratio_3D = m23D;
    result.Beam_Propagation_Ratio_3D_Uncertainty = m23D_unc;

    // 光束传播因子
    auto [k3D, k3D_unc] = getParameterWithUncertainty<double>(_iBeamQualityDocId,
        RayCi_BeamQuality_Analysis_Caustic3D_K_isValid,
        RayCi_BeamQuality_Analysis_Caustic3D_K_getK);
    result.Beam_Propagation_Factor_3D = k3D;
    result.Beam_Propagation_Factor_3D_Uncertainty = k3D_unc;

    // 内在散光
    auto [intrinsicAst, intrinsicAst_unc] = getParameterWithUncertainty<double>(_iBeamQualityDocId,
        RayCi_BeamQuality_Analysis_Caustic3D_IntrinsicAstigmatism_isValid,
        RayCi_BeamQuality_Analysis_Caustic3D_IntrinsicAstigmatism_getIntrinsicAstigmatism);
    result.Intrinsic_Astigmatism_3D = intrinsicAst;
    result.Intrinsic_Astigmatism_3D_Uncertainty = intrinsicAst_unc;
    return result;
}
//对于item操作
int Beam_Quality::getItemCount() const {
    int nItemCount = 0;
    RayCi_BeamQuality_Sequence_getItemCount(_iBeamQualityDocId, &nItemCount);
    return nItemCount;
}

QString Beam_Quality::getItemInfo(int index) const {
    char szInfo_buffer[80] = {0};
    int nSize = sizeof(szInfo_buffer);
    RayCi_BeamQuality_Sequence_Item_getInfoA(_iBeamQualityDocId, index, szInfo_buffer, &nSize);
    qDebug() << szInfo_buffer;
    return QString::fromLatin1(szInfo_buffer);
}

bool Beam_Quality::getItemEnabled(int index) const {
    bool bEnabled = false;
    RayCi_BeamQuality_Sequence_Item_isEnabled(_iBeamQualityDocId, index, &bEnabled);
    return bEnabled;
}

void Beam_Quality::setCurrentItem(int index) const {
    if(index < 0) return;
    RayCi_BeamQuality_Sequence_setCurrentItem(_iBeamQualityDocId, index);
}

void Beam_Quality::setItemEnabled(int index, bool enabled) const {
    if (index >= 0 && index < getItemCount()) {
        RayCi_BeamQuality_Sequence_Item_enable(_iBeamQualityDocId, index, enabled);
    }
}
void Beam_Quality::setItemMoveUp(int index) const {
    if (index > 0 && index < getItemCount()) {
        RayCi_BeamQuality_Sequence_moveItem(_iBeamQualityDocId, index, index - 1);
    }
}

void Beam_Quality::setItemMoveDown(int index) const {
    if (index >= 0 && index < getItemCount() - 1) {
        RayCi_BeamQuality_Sequence_moveItem(_iBeamQualityDocId, index, index + 1);
    }
}

void Beam_Quality::setItemRemove(int index) const {
    if (index >= 0 && index < getItemCount()) {
        RayCi_BeamQuality_Sequence_removeItem(_iBeamQualityDocId, index, 1);
    }
}
void Beam_Quality::setItemSort() const {
    bool bChanged;
    RayCi_BeamQuality_Sequence_sortItems(_iBeamQualityDocId, &bChanged);

}

void Beam_Quality::setItemRefresh()  {
    RayCi_BeamQuality_Sequence_refresh(_iBeamQualityDocId);

    QVector<QString> itemInfos;
    QVector<bool> itensEnabled;
    int itemCount = getItemCount();
    for (int i = 0; i < itemCount; ++i) {
        int bufferSize = 256;
        bool check=false;
        char* infoBuffer = new char[bufferSize];
        int result = RayCi_BeamQuality_Sequence_Item_getInfoA(_iBeamQualityDocId, i, infoBuffer, &bufferSize);
        int checked= RayCi_BeamQuality_Sequence_Item_isEnabled(_iBeamQualityDocId, i, &check);
        if (result == 0) {
            itemInfos.append(QString(infoBuffer));
            itensEnabled.append(checked);
        } else {
            itemInfos.append(QString("Error loading item info"));
            itensEnabled.append(false);
        }
        delete[] infoBuffer;
    }
    emit BeamQualitySequenceRefreshed(itemInfos, itensEnabled);;
}


void Beam_Quality::exportReport() {
    RayCi_createDirectoryA("C:\\RayCi\\BeamQuality");
    OPENFILENAMEA ofn;
    char szFile[260] = { 0 };
    ZeroMemory(&ofn, sizeof(ofn));
    ofn.lStructSize = sizeof(ofn);
    ofn.hwndOwner = GetActiveWindow();   ofn.lpstrFile = szFile;
    ofn.nMaxFile = sizeof(szFile) - 1;
    ofn.lpstrFilter = "PDF Files(*.pdf)\0*.pdf*\0All Files(*.*)\0*.*\0\0";
    ofn.nFilterIndex = 1;
    ofn.lpstrInitialDir = "C:\\RayCi\\BeamQuality";
    ofn.lpstrTitle = "Save Report As";
    ofn.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT;

    if (GetSaveFileNameA(&ofn) == TRUE) {
        const char* reportPathName = ofn.lpstrFile;
        std::string reportPathWithExtension = std::string(reportPathName) + ".pdf";
        RayCi_BeamQuality_Report_exportA(_iBeamQualityDocId, reportPathWithExtension.c_str());
        ShellExecuteA(nullptr, "open", reportPathWithExtension.c_str(), nullptr, nullptr, SW_SHOWNORMAL);
    } else {
        DWORD error = CommDlgExtendedError();
        if (error != 0) {
        }
        MessageBoxA(nullptr, "Export was cancelled.", "Info", MB_OK | MB_ICONINFORMATION);
    }
}

void Beam_Quality::close(bool bWaitWhileClosing) {

     RayCi_BeamQuality_closeAll(bWaitWhileClosing);
    _iBeamQualityDocId=0;
     m_batchData.clear();
     m_beamQualityResultsImage.clear();
     ResultImageVis.clear();
}

void Beam_Quality::clear() {
    _iBeamQualityDocId=0;

    m_batchData.clear();
    m_beamQualityResultsImage.clear();
    ResultImageVis.clear();
}


bool Beam_Quality::isValid() const {
    bool bValid = false;
    RayCi_BeamQuality_isValid(_iBeamQualityDocId, &bValid);
    return bValid;
}

bool Beam_Quality::isModified() const {
    bool bModified = false;
    RayCi_BeamQuality_isModified(_iBeamQualityDocId, &bModified);
    return bModified;
}

QString Beam_Quality::getPathName() const {
    wchar_t szPathName_buffer[260] = {0};
    int nSize = sizeof(szPathName_buffer);
    RayCi_BeamQuality_getPathNameW(_iBeamQualityDocId, szPathName_buffer, &nSize);
    return QString::fromWCharArray(szPathName_buffer);
}

bool Beam_Quality::isProcessing() const {
    return m_isProcessing;
}

bool Beam_Quality::isSaving() const {
    return m_isSaving;
}

bool Beam_Quality::cropToAOI(double dExtraOuterArea) {
    if (m_isProcessing) {
        return false;
    }

    m_isProcessing = true;
    bool result = RayCi_BeamQuality_Processing_Transform_cropToAoi(_iBeamQualityDocId, dExtraOuterArea);
    return result;
}

bool Beam_Quality::binning2x2() {
    if (m_isProcessing) {
        return false;
    }

    m_isProcessing = true;
    bool result = RayCi_BeamQuality_Processing_Transform_binning2x2(_iBeamQualityDocId);
    return result;
}

bool Beam_Quality::checkProcessingStatus() {
    bool isRunning = false;
    RayCi_BeamQuality_Processing_isProcessRunning(_iBeamQualityDocId, &isRunning);

    if (!isRunning) {
        m_isProcessing = false;
    }

    return isRunning;
}

bool Beam_Quality::saveDocument() {
    //if (!isValid()) return false;


    QString path = getPathName();
    if (path.isEmpty()) {
        return false;
    }

    return saveAsDocument(path);
}

bool Beam_Quality::saveAsDocument(const QString& filePath) {
    // if (!isValid() || filePath.isEmpty()) {
    //     return false;
    // }
    if (filePath.isEmpty()) {
        return false;
    }


    m_isSaving = true;
    std::wstring wPath = filePath.toStdWString();
    bool result = RayCi_BeamQuality_saveAsW(_iBeamQualityDocId, wPath.c_str(), true);
    m_isSaving = false;

    return result;
}